package com.substanceofcode.data.midp;

import java.util.Enumeration;

import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import javax.microedition.lcdui.*;

import net.sf.microlog.core.Logger;
import net.sf.microlog.core.LoggerFactory;
import net.sf.microlog.core.appender.ConsoleAppender;

import junitj2me.framework.TestFailure;
import junitj2me.framework.TestResult;
import junitj2me.framework.TestSuite;

public class RsfsMIDletTest extends MIDlet
{

    private final static Logger Logger = null;

    static
    {
        Logger Logger = LoggerFactory.getLogger();
        Logger.addAppender( new ConsoleAppender() );
    }

    public RsfsMIDletTest()
    {
        iMIDletInstance = this;
    }

    protected void destroyApp( boolean arg0 ) throws MIDletStateChangeException
    {
        // TODO Auto-generated method stub

    }

    protected void pauseApp()
    {
        // TODO Auto-generated method stub

    }

    protected void startApp() throws MIDletStateChangeException
    {
        RecordStoreFormTest form = new RecordStoreFormTest();
        Display display = Display.getDisplay( this );
        display.setCurrent( form );

        // Speed up testing -- run all tests automatically on startup.
        form.commandAction( RecordStoreFormTest.COMMAND_RUN_ALL_TESTS, form );

    }

    public void close()
    {
        try
        {
            destroyApp( false );
            notifyDestroyed();
        }
        catch( MIDletStateChangeException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static MIDlet iMIDletInstance;
}

class RecordStoreFormTest extends Form implements CommandListener
{
    private final static Logger        Logger        = LoggerFactory.getLogger();

    private static final TestCommand[] iTestCommands = { new TestCommand( RsfsListTest.class ), new TestCommand( RsfsFormatTest.class ), new TestCommand( RsfsFileTest.class ),
            new TestCommand( RsfsSplitFileTest.class ) };

    //private static final TestCommand[] iTestCommands = { new TestCommand( RsfsINodeTableTest.class ), new TestCommand( RsfsTest.class ),
    //        new TestCommand( RsfsDirectoryTest.class ), new TestCommand( RsfsMultipleFilesInDirectoryTest.class ),
    //        new TestCommand( RsfsSetRecordStoreTest.class ) };

    public RecordStoreFormTest()
    {
        super( "RecordStoreFormTest" );

        setCommandListener( this );

        append( "Hello" );

        doAdjustCommands();
    }

    protected void doAdjustCommands()
    {
        //super.doAdjustCommands();

        this.addCommand( COMMAND_RUN_ALL_TESTS );
        for( int i = 0; i < iTestCommands.length; ++i )
        {
            this.addCommand( iTestCommands[i] );
        }
        this.addCommand( COMMAND_EXIT );
    }

    public void commandAction( Command aCommand, Displayable aDisplayable )
    {
        if( COMMAND_EXIT == aCommand )
        {
            ( (RsfsMIDletTest) RsfsMIDletTest.iMIDletInstance ).close();
        }
        else if( COMMAND_RUN_ALL_TESTS == aCommand )
        {
            try
            {
                runAllTests();
            }
            catch( Exception e )
            {
                Logger.error( "runTests() threw an exception", e );
            }
        }
        else if( aCommand instanceof TestCommand )
        {
            runOneTest( ( (TestCommand) aCommand ).getTestClass() );
        }
        else
        {
            //super.commandAction( aCommand, aDisplayable );
        }
    }

    public static class TestCommand extends Command
    {
        TestCommand( Class aTestClass )
        {
            super( aTestClass.getName().substring( aTestClass.getName().lastIndexOf( '.' ) + 1 ), Command.SCREEN, 100 + ( ++iTestRunnerCommandPriorityNumber ) );

            iTestClass = aTestClass;
        }

        public Class getTestClass()
        {
            return iTestClass;
        }

        Class iTestClass;
    }

    private void appendStringItem( String aLabel, String aText )
    {
        Item item = new StringItem( aLabel, aText );
        item.setLayout( Item.LAYOUT_NEWLINE_BEFORE );
        append( item );
    }

    private void runAllTests() throws Exception
    {
        TestResult testResult = new TestResult();

        for( int i = 0; i < iTestCommands.length; ++i )
        {

            Class clazz = iTestCommands[i].getTestClass();
            appendStringItem( "Running", clazz.toString() );

            long initialElapsedTime = testResult.totalElapsedTime();

            new TestSuite( clazz ).run( testResult );

            long elapsedTimeThisTest = testResult.totalElapsedTime() - initialElapsedTime;

            appendStringItem( "Elapsed ", Long.toString( elapsedTimeThisTest ) );

        }

        logTestResult( testResult );
    }

    private void runOneTest( Class aTestClass )
    {
        TestResult testResult = new TestResult();

        appendStringItem( "Running", testResult.toString() );

        new TestSuite( aTestClass ).run( testResult );

        logTestResult( testResult );
    }

    private void logTestResult( TestResult aTestResult )
    {
        StringBuffer buffer = new StringBuffer();
        String message = null;

        if( 0 == aTestResult.runCount() )
        {
            buffer.append( "ERROR, NO TESTS RAN" );
            message = buffer.toString();

            Logger.info( message );
        }
        else
        {
            if( aTestResult.wasSuccessful() )
            {
                buffer.append( "ALL " );
                buffer.append( aTestResult.runCount() );
                buffer.append( " TESTS PASSED!" );
                message = buffer.toString();

                Logger.info( message );
            }
            else
            {
                buffer.append( "PROBLEMS among " );
                buffer.append( aTestResult.runCount() );
                buffer.append( " tests: failures: " );
                buffer.append( aTestResult.failureCount() );
                buffer.append( " errors: " );
                buffer.append( aTestResult.errorCount() );
                message = buffer.toString();

                Logger.info( message );

                for( Enumeration failures = aTestResult.failures(); failures.hasMoreElements(); )
                {
                    TestFailure testFailure = (TestFailure) failures.nextElement();
                    message = testFailure.toString();
                    Logger.info( message );

                    buffer.append( "\n" );
                    buffer.append( message );
                }

                for( Enumeration errors = aTestResult.errors(); errors.hasMoreElements(); )
                {
                    TestFailure testFailure = (TestFailure) errors.nextElement();

                    message = testFailure.toString();
                    Logger.info( message );

                    buffer.append( "\n" );
                    buffer.append( message );
                }
            }
        }

        String summary = buffer.toString();
        appendStringItem( "Result ", summary );

        appendStringItem( "Total elapsed", Long.toString( aTestResult.totalElapsedTime() ) );

        Alert alert = new Alert( "Test Results", summary, null, AlertType.INFO );
        alert.setTimeout( 3 * 1000 );
        Display display = Display.getDisplay( RsfsMIDletTest.iMIDletInstance );
        display.setCurrent( alert, display.getCurrent() );
    }

    private static final Command COMMAND_EXIT                     = new Command( "Exit", Command.BACK, 2 );
    static final Command         COMMAND_RUN_ALL_TESTS            = new Command( "All tests", Command.SCREEN, 100 );

    private static int           iTestRunnerCommandPriorityNumber = 0;

}
